/*
 * @Author: hongbin
 * @Date: 2022-11-23 11:26:49
 * @LastEditors: hongbin
 * @LastEditTime: 2022-11-30 16:51:35
 * @Description:初始化自定义形象环境
 */
import {
    HemisphereLight,
    PerspectiveCamera,
    Scene,
    WebGLRenderer,
    AxesHelper,
    DirectionalLight,
    FogExp2,
    Color,
    MeshStandardMaterial,
} from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { get } from "../api";
import { IPart, IPartConfig } from "../components/CustomProfile/types";
import { AnimationPlayer } from "../meta/helper";
import { clearChildren } from "../meta/helper/clearChildren";
import { loadGltf } from "../meta/helper/loaderHelper";
import { RandomColor } from "../meta/utils";

// const m = new MeshStandardMaterial({})

const scene = new Scene();
let renderer: WebGLRenderer;
let camera: PerspectiveCamera;
const acterPlayer = AnimationPlayer();
let actorScene: THREE.Group;
let actorAnimations: THREE.AnimationClip[];

function render() {
    renderer.render(scene, camera);
}

export const init = (parameters: THREE.WebGLRendererParameters) => {
    scene.add(new AxesHelper(100));
    const canvas = parameters.canvas as HTMLCanvasElement;

    // camera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 500);
    camera = new PerspectiveCamera(75, canvas.offsetWidth / canvas.offsetHeight, 1, 500);
    camera.name = "camera";
    camera.position.set(0, 15, 25);
    scene.add(camera);

    const hemisphereLight = new HemisphereLight(0xeeeeff, 0x777788, 1);
    hemisphereLight.position.set(0, 10, 0.75);
    const directionalLight = new DirectionalLight(0xffffff, 0.5);
    directionalLight.position.set(0, 10, 4);
    scene.add(hemisphereLight, directionalLight);

    renderer = new WebGLRenderer(parameters);
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(canvas.offsetWidth, canvas.offsetHeight);
    // scene.background = new RandomColor();
    scene.background = new Color("#2D5B1A");
    // const fog = new FogExp2(scene.background as ignore, 0.02);
    // scene.fog = fog;

    function onWindowResize() {
        camera.aspect = canvas.offsetWidth / canvas.offsetHeight;
        camera.updateProjectionMatrix();

        renderer.setSize(canvas.offsetWidth, canvas.offsetHeight);
        render();
    }

    window.addEventListener("resize", onWindowResize);

    const controls = new OrbitControls(camera, renderer.domElement);

    controls.minDistance = 1;
    controls.maxPolarAngle = Math.PI / 2;
    // controls.minDistance = 1;
    controls.target.set(0, 10, 0);
    controls.update();
    /**
     * 按需渲染
     * TODO
     */
    controls.addEventListener("change", () => {
        render();
        acterPlayer.start();
    });

    render();
    loadActorModel();

    loadPartsModel();
};

init.clear = () => {
    //清除监听和旧的模型
    console.log("清除缓存");
    clearChildren(scene as unknown as THREEMesh);
};

/**
 * 添加配件到人物模型上
 */
export function addPartsToActor(wearParts: IPart[], partsConfig: Record<string, IPartConfig>) {
    if (!actorScene) return new Error("未获取到人物模型");
    const animations: THREE.AnimationClip[] = [];
    wearParts.forEach((part) => {
        const config = partsConfig[part.name];
        const mesh = part.scene.children[0] as THREE.Mesh;
        if (!mesh) return console.error("没有mesh：", part);
        const material = mesh.material as THREE.MeshStandardMaterial;
        material.color = new Color(config.color);
        material.transparent = true;
        material.opacity = config.opacity;
        material.metalness = config.metalness;
        actorScene.add(part.scene);
        animations.push(...part.animations);
    });
    acterPlayer.init(actorScene, [...animations, ...actorAnimations]);
    render();
}
/**
 * 从人物模型上删除配件
 */
export function removePartsFromActor(wearParts: IPart[]) {
    if (!actorScene) return new Error("未获取到人物模型");

    wearParts.forEach((part) => {
        actorScene.remove(part.scene);
    });
    // acterPlayer.stop();
    render();
}

/**
 * 加载基本的人物模型
 */
function loadActorModel() {
    loadGltf("api/glb?name=acter.glb").then(async (acterGlb) => {
        acterGlb.scene.name = "acter";
        console.log(acterGlb);
        scene.add(acterGlb.scene);
        acterGlb.scene.rotateY(Math.PI);
        actorScene = acterGlb.scene;
        actorAnimations = acterGlb.animations;
        render();
        acterPlayer.init(acterGlb.scene, acterGlb.animations);
        //逐帧更新
        // const tick = () => {
        //     requestAnimationFrame(tick);
        //     acterPlayer.start();
        //     render();
        // };
        //TODO
        // tick();
    });
}
init.loadPartsModel = loadPartsModel;

/**
 * 加载配件
 */
async function loadPartsModel() {
    /**
     * 获取已有的全部配件列表
     */
    const { data: partsList } = await get<{ data: string[] }>("/parts/list");
    if (!partsList) return new Error("获取配件列表失败！");

    console.log(partsList);
    partsList.forEach((partName) => {
        loadGltf(`api/parts/query?name=${partName}`).then((model) => {
            // acterGlb.scene.add(part.scene);
            // console.log(part);
            // if (part.animations) {
            //     acterPlayer.init(acterGlb.scene, [...acterGlb.animations, ...part.animations]);
            // }
            // render();

            const animations = model.animations;
            const scene = model.scene;
            const { modelName: name, type } = model.scene.children[0].userData as Record<string, string>;

            const part = { animations, scene, name, type };
            loadPartsModel._change(part);
        });
    });
}

loadPartsModel._change = (part: IPart) => {};

loadPartsModel.change = (callback: (part: IPart) => void) => {
    loadPartsModel._change = callback;
};
